package org.dea.deploy;

import java.rmi.Naming;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

import org.dea.facade.DEAFacades;
import org.dea.interfaces.DistributedEasyAcceptFacade;
import org.dea.mapping.DistributedComponent;
import org.dea.mapping.EasyAcceptMappingReader;
import org.dea.util.GenericCommandLineExecutor;
import org.dea.util.ProcessOutput;

public class LocalhostDeploy {
	
	private static final int MAX_ERROR = 5;

	public void deploy( String classPath, String facade, int port ) throws Exception{
		String[] cmd = { "java", "-cp", classPath, "RMI"+facade, String.valueOf( port ) };
		GenericCommandLineExecutor exec = new GenericCommandLineExecutor(cmd);
		exec.runCommand();
	}
	
	public ProcessOutput[] deployAll( String classPath, String mapping, DEAFacades facades ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		return deployAll(classPath, map, facades);
	}

	public ProcessOutput[] deployAll(String classPath, Map<String, DistributedComponent> map, DEAFacades facades ) throws Exception, InterruptedException {
		Set<String> keys = map.keySet();
		ProcessOutput[] output = new ProcessOutput[keys.size()];
		GenericCommandLineExecutor[] exec = new GenericCommandLineExecutor[keys.size()];
		int i = 0;
		for (String key : keys) {
			DistributedComponent comp = map.get(key);
			String[] cmd = getCMD(classPath, comp, facades );
			exec[i] = new GenericCommandLineExecutor(cmd);
			exec[i].runCommand();
			output[i] = new ProcessOutput( Arrays.toString(cmd),"", "" );
			i++;
		}
		
		Thread.sleep(2000);
		this.pingAll(map);
		for (int j = 0; j < exec.length; j++) {
			output[j].setErr(exec[j].getErrOutput());
			output[j].setStd(exec[j].getStdOutput());
		}
		return output;
	}
	
	@Deprecated
	public ProcessOutput[] deployAll( String classPath, String mapping ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		return deployAll(classPath, map );
	}
	@Deprecated
	public ProcessOutput[] deployAll(String classPath, Map<String, DistributedComponent> map ) throws Exception, InterruptedException {
		Set<String> keys = map.keySet();
		ProcessOutput[] output = new ProcessOutput[keys.size()];
		GenericCommandLineExecutor[] exec = new GenericCommandLineExecutor[keys.size()];
		int i = 0;
		for (String key : keys) {
			DistributedComponent comp = map.get(key);
			String[] cmd = getCMD(classPath, comp );
			exec[i] = new GenericCommandLineExecutor(cmd);
			exec[i].runCommand();
			output[i] = new ProcessOutput( Arrays.toString(cmd),"", "" );
			i++;
		}
		
		Thread.sleep(2000);
		this.pingAll(map);
		for (int j = 0; j < exec.length; j++) {
			output[j].setErr(exec[j].getErrOutput());
			output[j].setStd(exec[j].getStdOutput());
		}
		return output;
	}

	
	public void shutdownAll( String mapping ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		shutdownAll(map);
	}

	public void shutdownAll(Map<String, DistributedComponent> map) throws InterruptedException {
		Set<String> keys = map.keySet();
		for (String key : keys) {
			DistributedComponent cpm = map.get(key);
	        try{
	        	DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup("rmi://"+ cpm.getHostAddress() + ":" + cpm.getHostPort() +"/IF"+cpm.getFacade());
	        	facade.distributedEasyAcceptShutdown();
	        } catch (Exception ex){
	        	
	        }
		}
		Thread.sleep(2000);
	}
	
	
	public boolean pingAll( String mapping ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		return pingAll(map);
	}

	public boolean pingAll(Map<String, DistributedComponent> map) throws InterruptedException {
		Set<String> keys = map.keySet();
		for (String key : keys) {
			
			DistributedComponent cpm = map.get(key);
			for (int i = 0; i < MAX_ERROR; i++) {
		        try{
		        	DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup("rmi://"+ cpm.getHostAddress() + ":" + cpm.getHostPort() +"/IF"+cpm.getFacade());
		        	if( !facade.distributedEasyAcceptPing() ){
		        		return false;
		        	}else{
		        		System.out.println("deployed "+cpm);
		        		break;
		        	}
		        } catch (Exception ex){
		        	if( i==MAX_ERROR-1){
		        		return false;
		        	}else{
			        	Thread.sleep(1000);		        		
		        	}
		        }				
			}

		}
		return true;
	}
	
	private String[] getCMD(String classPath, DistributedComponent comp, DEAFacades facades) {
		String[] cmd = { "java", "-cp", classPath, facades.getRmiFacade(), String.valueOf(comp.getHostPort()) };
		
		if( comp.getArgs() != null && comp.getArgs().length() > 0){ 
			String[] args = comp.getArgs().split(" ");
			cmd = new String[5+ args.length];
			cmd[0]="java";
			cmd[1]="-cp";
			cmd[2]=classPath;
			cmd[3]=facades.getRmiFacade();
			cmd[4]=String.valueOf(comp.getHostPort());
			for(int i = 0; i<args.length; i++ ){
				cmd[i+5] = args[i];
			}
		}
		
		return cmd;
	}
	
	@Deprecated
	private String[] getCMD(String classPath, DistributedComponent comp) {
		String[] cmd = { "java", "-cp", classPath, "RMI"+comp.getFacade(), String.valueOf(comp.getHostPort()) };
		
		if( comp.getArgs() != null && comp.getArgs().length() > 0){ 
			String[] args = comp.getArgs().split(" ");
			cmd = new String[5+ args.length];
			cmd[0]="java";
			cmd[1]="-cp";
			cmd[2]=classPath;
			cmd[3]=comp.getFacade();
			cmd[4]=String.valueOf(comp.getHostPort());
			for(int i = 0; i<args.length; i++ ){
				cmd[i+5] = args[i];
			}
		}
		
		return cmd;
	}

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		LocalhostDeploy deployer = new LocalhostDeploy();
		if( args.length < 3 ){
			System.err.println("Usage: java org.dea.deploy.LocalhostDeploy <deploy|undeploy> <classpath> <facade>");
		}
		if( args[0].trim().toLowerCase().equals("deploy") ){
			deployer.deployAll( args[1].trim(), args[2].trim() );			
		}else if( args[0].trim().toLowerCase().equals("undeploy") ){
			deployer.shutdownAll( args[2].trim() );
		}else{
			System.err.println("Usage: java org.dea.deploy.LocalhostDeploy <deploy|undeploy> <classpath> <facade>");
		}
	}

}
